package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import entities.Location;

import server.ServerConstants;
import server.Statistics;
import simulation.Simulation;
import simulation.SimulationConstants;

public class RandomClient extends Thread{
	private int portNumber;
	private double querySendMaxTime;
	private double queryPollMaxTime;
	private double movingtime;
	private boolean running;
	private Random rand;
	private int senderId;
	private static int sends;
	private BufferedReader input = null;
	private PrintStream output = null;
	private Socket client = null;
	private String response = null;
	private MovementSimulator ms;
	private Location loc;

	public RandomClient(int portNumber, int senderId) {
		this.portNumber = portNumber;
		running = true; 
		rand = new Random();
		
		this.senderId = senderId;
		sends = 0;
		ms = new MovementSimulator();
		
		loc = ms.generateLocation();
	}

	public void run(){
		int pollSleep = rand.nextInt((int)queryPollMaxTime);
		int sendSleep = rand.nextInt((int)querySendMaxTime);
		int movSleep = rand.nextInt((int)movingtime);
		while(running){
			try {
				if (pollSleep <= 0) {
					pollSleep = rand.nextInt((int)queryPollMaxTime);
					pollServer();
				}
				if(sendSleep <= 0) {
					sendSleep = rand.nextInt((int)querySendMaxTime);
					sendMessageToServer();
				}
				if(movSleep <= 0){
					movSleep =  rand.nextInt((int)movingtime);
					ms.move(loc);
				}
				int min = Math.min(pollSleep, sendSleep);
				pollSleep -= min;
				sendSleep -= min;
				sleep(min);

			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public synchronized int getSends(){
		return sends++;
	}
	
	public void send() throws IOException{
		//logger.info(String.valueOf(getSends()));
		output.println(ServerConstants.SEND);
		response = input.readLine();
		if (response == null) {
			System.out.println("ERROR in RandomClient, response on SEND was NULL, expected OK");
		}
		else {
			String id = String.valueOf(Simulation.getMessageId());
			String senderId = String.valueOf(this.senderId);
			String latitude = String.valueOf(loc.getLatitude());
			String longitude = String.valueOf(loc.getLongitude());
			String message = "Today I programmed a program and the program was great!";
			output.println(id + ";" + senderId + ";" + latitude + ";" + longitude + ";" + message);
		}
	}

	public void sendMessageToServer(){
		try {
			connect();
			send();
			closeConnections();
		}
		catch (UnknownHostException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void poll() throws IOException {
		output.println(ServerConstants.POLL);

		// Should be OK, no need to check though.
		response = input.readLine();
		if(response == null) {
			System.out.println("ERROR in RandomClient, response on POLL was NULL, expected OK");
		}
		else {
			// Send our location
			output.println(senderId + ";" + loc.getLatitude() + ";" + loc.getLongitude());
			// Got all messages within our area.. 
			response = input.readLine();
			// We don't have anything to do with these...
			while(response != null){
				//System.out.println(response);
				response = input.readLine();
			}
		}
	}

	public void connect() throws UnknownHostException, IOException {
		client = new Socket(ServerConstants.IP_ADDRESS, portNumber);
		input = new BufferedReader(new InputStreamReader(client.getInputStream()));
		output = new PrintStream(client.getOutputStream());
	}

	public void pollServer() {
		// Create a connection
		try {
			connect();
			poll();
			closeConnections();
		}
		catch (UnknownHostException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void closeConnections() throws IOException{
		output.close();
		input.close();
		client.close();
	}

	public synchronized void close() {
		running = false;
	}

	public void setNormalMode(){
		querySendMaxTime = SimulationConstants.NORMAL_QUERY_SEND_LOAD;
		queryPollMaxTime = SimulationConstants.NORMAL_QUERY_POLL_LOAD;
	}

	public void setHighMessageLoad(){
		querySendMaxTime = SimulationConstants.HIGH_QUERY_SEND_LOAD;
		queryPollMaxTime = SimulationConstants.NORMAL_QUERY_POLL_LOAD;
	}

	public void setHighPollingLoad(){
		querySendMaxTime = SimulationConstants.NORMAL_QUERY_SEND_LOAD;
		queryPollMaxTime = SimulationConstants.HIGH_QUERY_POLL_LOAD;
	}

	public void setHighLoad(){
		querySendMaxTime = SimulationConstants.HIGH_QUERY_SEND_LOAD;
		queryPollMaxTime = SimulationConstants.HIGH_QUERY_POLL_LOAD;
		movingtime = SimulationConstants.HIGH_MOVEMENT;
	}
}
